## ---- load_functions, include = FALSE ----

# Replication archive version - no scholr package dependency
# Functions like set_label_mappings() and convert_labels() are defined in text_packages_rep.R

add_comma <- function(x, ...) {
    format(x, ..., big.mark = ",", scientific = FALSE, trim = TRUE)
}

number_to_word <- function(x) {
    ifelse(x > 10, x, c("one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten")[x])
}


# =============================================================================
# Project-specific label mappings for convert_labels()
# =============================================================================
# These mappings use regex patterns as keys and human-readable labels as values.
# They are registered with set_label_mappings() and applied automatically.
# The mappings are organized by category for maintainability.

text_label_mappings <- c(

    # --- Expressive Alignment / Engagement scales ---
    "^nchar_align_.*ihs$"                    = "Expressive Alignment 2016",
    "nchar_align_.*ihs:pid.*Dem"             = "Expressive Alignment 2016 x Dem",
    "nchar_align_.*ihs:pid.*Ind"             = "Expressive Alignment 2016 x Ind",
    "nchar_align_.*ihs:pid.*Rep"             = "Expressive Alignment 2016 x Rep",
    "nchar_align_.*ihs:pid.*Oth"             = "Expressive Alignment 2016 x Other",

    "^nonresp_nchar_all(_log)?$"             = "Expressive Alignment 2016",
    "nonresp_nchar_all(_log)?:pid.*Dem"      = "Expressive Alignment x Dem",
    "nonresp_nchar_all(_log)?:pid.*Ind"      = "Expressive Alignment x Ind",
    "nonresp_nchar_all(_log)?:pid.*Rep"      = "Expressive Alignment x Rep",
    "nonresp_nchar_all(_log)?:pid.*Oth"      = "Expressive Alignment x Other",

    "nchar_problems.*_ihs$"                  = "Expressive Engagement 2016",
    "nchar_problems_.*_.*$"                  = "Expressive Engagement 2016",
    "nchar_problems20_ihs$"                  = "Expressive Engagement 2020 (Continuous)",
    "nchar_prob20_tot_ihs$"                  = "Expressive Engagement 2020 (Alt)",
    "nchar_problems20_bin"                   = "Expressive Engagement 2020 (Binary)",
    "nchar_problems20_fct.*"                 = "Expressive Engagement 2020",

    "nchar_problems_.*:pid.*Dem"             = "Expressive Engagement 2016 x Democrat",
    "nchar_problems_.*:pid.*Ind"             = "Expressive Engagement 2016 x Independent",
    "nchar_problems_.*:pid.*Rep"             = "Expressive Engagement 2016 x Republican",
    "nchar_problems_.*:pid.*Oth"             = "Expressive Engagement 2016 x Other",

    # --- Nonresponse scales ---
    "^nonresp_all16$"                        = "Nonresponse Scale",
    "nonresp_all16:pid.*Dem$"                = "Nonresponse Scale x Dem",
    "nonresp_all16:pid.*Ind$"                = "Nonresponse Scale x Ind",
    "nonresp_all16:pid.*Rep$"                = "Nonresponse Scale x Rep",
    "nonresp_all16:pid.*Oth$"                = "Nonresponse Scale x Oth",

    "^nonresp_lddr16$"                       = "\\# Nonresp (For Clinton + Against Trump)",
    "^nonresp_lddr16_fct[0-9]+$"             = "\\# Nonresp (For Clinton + Against Trump)",
    "^nonresp_lrdd16$"                       = "\\# Nonresp (For Trump + Against Clinton)",
    "^nonresp_lrdd16_fct[0-9]+$"             = "\\# Nonresp (For Trump + Against Clinton)",

    # --- Character counts ---
    "^nchar_lrdd$"                           = "\\# Characters (For Trump + Against Clinton)",
    "^nchar_lddr$"                           = "\\# Characters (For Clinton + Against Trump)",
    "nchar_like_dem(_log)?$"                 = "\\# Characters (For Clinton)",
    "nchar_like_rep(_log)?$"                 = "\\# Characters (For Trump)",

    "nchar_like_dem.*:pid.*Dem"              = "\\# Chars (For Clinton) x Dem",
    "nchar_like_dem.*:pid.*Ind"              = "\\# Chars (For Clinton) x Ind",
    "nchar_like_dem.*:pid.*Rep"              = "\\# Chars (For Clinton) x Rep",
    "nchar_like_dem.*:pid.*Oth"              = "\\# Chars (For Clinton) x Other",
    "nchar_like_rep.*:pid.*Dem"              = "\\# Chars (For Trump) x Dem",
    "nchar_like_rep.*:pid.*Ind"              = "\\# Chars (For Trump) x Ind",
    "nchar_like_rep.*:pid.*Rep"              = "\\# Chars (For Trump) x Rep",
    "nchar_like_rep.*:pid.*Oth"              = "\\# Chars (For Trump) x Other",

    # --- MIP (Most Important Problem) ---
    "^mip_1$"                                = "MIP Scale (0-1)",
    "nchar_nr_prob_tot$"                     = "Most Imp Prob Scale (\\# Chars + Nonresp)",
    "nchar_nr_prob_tot_log$"                 = "MIP Scale Logged (\\# Chars + Nonresp)",

    # --- Feeling thermometers ---
    "^ft_clinton$"                           = "Feeling Therm: Clinton",
    "^ft_biden$"                             = "Feeling Therm: Biden",
    "^ft_trump$"                             = "Feeling Therm: Trump 2016",
    "^ft_trump20$"                           = "Feeling Therm: Trump 2020",
    "^ft_trump_clinton$"                     = "Feeling Therm: Trump - Clinton",
    "^ft_trump_biden$"                       = "Feeling Therm: Trump - Biden",
    "^ft_dem$"                               = "Feeling Therm: Democrats",
    "^ft_rep$"                               = "Feeling Therm: Republicans",
    "^ft_rep_dem$"                           = "Feeling Therm: Reps - Dems",
    "^ft_conserv"                            = "Feeling Therm: Conservatives",
    "^ft_liberals"                           = "Feeling Therm: Liberals",

    # --- Voting / Turnout ---
    "^vote_pres_dem$"                        = "Vote Dem Pres",
    "^vote_pres_rep$"                        = "Vote GOP Pres",
    "turnout20_bin"                          = "Validated Turnout 2020",
    "likely_vote"                            = "Likely Vote",
    "reg16_bin|reg20_bin"                    = "Registered",

    # --- Demographics (with wave suffix flexibility) ---
    "^ideo7"                                 = "Ideology (1-7)",
    "^pid7_int"                              = "Party ID (Strong Dem = 1, Strong Rep = 7)",
    "^racial_resent"                         = "Racial Resentment",
    "^sexism"                                = "Hostile Sexism",
    "^authorit"                              = "Authoritarianism",
    "^age(?:16|20|24)?$"                     = "Age (yrs)",
    "^female.*Yes$"                          = "Female",
    "^education|^educ"                       = "Education",
    "^income"                                = "Income",
    "^pol_attn"                              = "Political Attention",
    "^civic$"                                = "Civic Engagement Scale",
    "^pk_scale$"                             = "Political Knowledge Scale",
    "^engage_scale$"                         = "Political Engagement Scale",
    "^pol_int$"                              = "Political Interest",

    # --- Survey mode ---
    "^mode.*[wW]eb$"                         = "Mode: Web",
    "^mode_pre20video$"                      = "Mode: Video",

    # --- Race categories ---
    "race.*[bB]lack"                         = "Race: Black",
    "race.*[hH]ispanic"                      = "Race: Hispanic",
    "race.*[wW]hite"                         = "Race: White",
    "race.*[nN]ative"                        = "Race: Native American",
    "race.*[mM]ultiple"                      = "Race: Multiple",
    "race.*[oO]ther"                         = "Race: Other",

    # --- Party ID ---
    "^pid.*Dem$|^party.*Dem$"                = "Party: Democrats",
    "^pid.*Ind$|^party.*Ind$"                = "Party: Independent",
    "^pid.*Rep$|^party.*Rep$"                = "Party: Republican",
    "^pid.*Oth$|^party.*Oth$"                = "Party: Other",

    # --- Interaction terms (racial resentment x party) ---
    "^racial_resent.*:pid.*Dem$"             = "Racial Resent. x Dem",
    "^racial_resent.*:pid.*Ind$"             = "Racial Resent. x Ind",
    "^racial_resent.*:pid.*Rep$"             = "Racial Resent. x Rep",
    "^racial_resent.*:pid.*Oth$"             = "Racial Resent. x Oth",

    # --- Afrobarometer ---
    "dem_importance$"                        = "Importance of Democracy",
    "dem_importance_mean$"                   = "Importance of Democracy (Mean)",
    "^langFrench$"                           = "Lang: French",
    "^langPortuguese$"                       = "Lang: Portuguese",
    "^langEnglish$"                          = "Lang: English",
    "^corrup$"                               = "Corruption",
    "^corrup_pres$"                          = "Corrupt President",
    "^corrup_parl$"                          = "Corrupt Parliament",
    "^corrup_local$"                         = "Corrupt Local Officials",
    "^home_dem$"                             = "Home Dem",

    # --- Asian American Partisanship study ---
    "^treatment_fctTreated$"                 = "Social Exclusion Treatment",
    "^asian_white_fctAsian$"                 = "Race: Asian (vs White)",
    "treatment_fctTreated:asian_white_fctAsian" = "Treated $\\times$ Asian",
    "asian_white_fctAsian:treatment_fctTreated" = "Asian $\\times$ Treated",
    "^time_min$"                             = "Time (min)",
    "I\\(time_min2\\)"                       = "Time$^2$ (min)",
    "asian_white_fctAsian:I\\(time_min2\\)"  = "Asian $\\times$ Time$^2$",
    "treatment_fctTreated:I\\(time_min2\\)"  = "Treated $\\times$ Time$^2$",
    "asian_white_fctAsian:treatment_fctTreated:I\\(time_min2\\)" = "Asian $\\times$ Treated $\\times$ Time$^2$"
)

# Register the project-specific mappings (function defined in text_packages_rep.R)
set_label_mappings(text_label_mappings, append = TRUE)


# =============================================================================
# convert_labels wrapper with LaTeX underscore escaping
# =============================================================================
# Store reference to base convert_labels from text_packages_rep.R before overwriting
.base_convert_labels <- convert_labels

# Wrapper that adds LaTeX underscore escaping
convert_labels <- function(model, extracted = FALSE) {
    labels <- .base_convert_labels(model, extracted = extracted, use_defaults = TRUE)
    # Escape any remaining underscores that weren't converted to labels
    # (protects against LaTeX errors from unmatched variable names)
    labels <- stringr::str_replace_all(labels, "(?<!\\\\)_", "\\\\_")
    return(labels)
}


# plot_model wrapper (DEPRECATED - use plot_model directly with type = "eff")
# Kept for backwards compatibility; prefer direct plot_model calls in new code
pm2 <- function(model, type = "eff", terms) {
    sjPlot::plot_model(model = model, terms = terms, type = type,
                       colors = c(Dem = "#013388", Rep = "#cc0000", Ind = "mediumpurple", Unreg = "#cbcaca")) +
        aes(linetype = group, color = group) +
        scale_y_continuous(limits = c(0, 1),
                           labels = scales::percent_format(accuracy = 1)) +
        labs(title = element_blank(), linetype = "Party ID", color = "Party ID")
}



# r anova-print-functions, include = FALSE
round1 <- function(x) {round(as.numeric(x), 1)}

round2 <- function(x) {round(as.numeric(x), 2)}

na_to_dash <- function(x) {
    x <- as.character(x)
    ifelse(is.na(x) | x == "NA", "-", x)
}

na_to_blank <- function(x) {
    x <- as.character(x)
    ifelse(is.na(x) | x == "NA", "", x)
}

convert_model <- function(x) {
    x %>% str_replace("\\*", "x") %>%
        str_replace("^pid3_16Dem$",          "Party ID: Dem") %>%
        str_replace("^pid3_16Ind$",          "Party ID: Ind") %>%
        str_replace("^pid3_16Rep$",          "Party ID: Rep") %>%
        str_replace("^pid3_16$",             "Party ID (excl. Other)") %>%
        str_replace("^pid(?:3|4)(?:_(?:16|20|24))?Dem$",          "Party ID: Dem") %>%
        str_replace("^pid(?:3|4)(?:_(?:16|20|24))?Ind$",          "Party ID: Ind") %>%
        str_replace("^pid(?:3|4)(?:_(?:16|20|24))?Rep$",          "Party ID: Rep") %>%
        str_replace("^pid(?:3|4)(?:_(?:16|20|24))?Other$",        "Party ID: Other") %>%
        str_replace("^pid(?:3|4)(?:_(?:16|20|24))?$",             "Party ID") %>%
        str_replace("^ideo7(?:_20)?$",       "Ideology (1-7)") %>%
        str_replace("^ft_clinton$",          "Feeling Therm: Clinton") %>%
        str_replace("^ft_trump20$",          "Feeling Therm: Trump 2020") %>%
        str_replace("^ft_trump$",            "Feeling Therm: Trump 2016") %>%

        str_replace("mode[wW]eb",            "Survey Mode") %>%
        str_replace("female(?:16|20|24)?",             "Female") %>%
        str_replace("educ$|education(?:16|20|24)?",    "Education") %>%
        str_replace("age",                "Age") %>%

        str_replace("^pol_correct_fct3Low Concern",                        "Norms: Low") %>%
        str_replace("^pol_correct_fct3Moderate Concern",                   "Norms: Moderate") %>%
        str_replace("^pol_correct_fct3High Concern",                       "Norms: High") %>%
        str_replace("^racial_resent(?:16|20|24)?:pol_correct_fct3Moderate Concern",            "Racial Resent. x Norms: Moderate") %>%
        str_replace("^racial_resent(?:16|20|24)?:pol_correct_fct3High Concern",                "Racial Resent. x Norms: High") %>%
        str_replace("^pid(?:3|4)(?:_(?:16|20|24))?Dem:pol_correct_fct3Moderate Concern",           "Dem x Norms: Moderate") %>%
        str_replace("^pid(?:3|4)(?:_(?:16|20|24))?Rep:pol_correct_fct3Moderate Concern",           "Rep x Norms: Moderate") %>%
        str_replace("^pid(?:3|4)(?:_(?:16|20|24))?Oth:pol_correct_fct3Moderate Concern",         "Oth x Norms: Moderate") %>%
        str_replace("^pid(?:3|4)(?:_(?:16|20|24))?Dem:pol_correct_fct3High Concern",               "Dem x Norms: High") %>%
        str_replace("^pid(?:3|4)(?:_(?:16|20|24))?Rep:pol_correct_fct3High Concern",               "Rep x Norms: High") %>%
        str_replace("^pid(?:3|4)(?:_(?:16|20|24))?Oth:pol_correct_fct3High Concern",             "Oth x Norms: High") %>%
        str_replace("^racial_resent(?:16|20|24)?:pid(?:3|4)(?:_(?:16|20|24))?Dem:pol_correct_fct3Moderate Concern",    "Racial Resent. x Dem x Norms: Moderate") %>%
        str_replace("^racial_resent(?:16|20|24)?:pid(?:3|4)(?:_(?:16|20|24))?Rep:pol_correct_fct3Moderate Concern",    "Racial Resent. x Rep x Norms: Moderate") %>%
        str_replace("^racial_resent(?:16|20|24)?:pid(?:3|4)(?:_(?:16|20|24))?Oth:pol_correct_fct3Moderate Concern",  "Racial Resent. x Oth x Norms: Moderate") %>%
        str_replace("^racial_resent(?:16|20|24)?:pid(?:3|4)(?:_(?:16|20|24))?Dem:pol_correct_fct3High Concern",        "Racial Resent. x Dem x Norms: High") %>%
        str_replace("^racial_resent(?:16|20|24)?:pid(?:3|4)(?:_(?:16|20|24))?Rep:pol_correct_fct3High Concern",        "Racial Resent. x Rep x Norms: High") %>%
        str_replace("^racial_resent(?:16|20|24)?:pid(?:3|4)(?:_(?:16|20|24))?Oth:pol_correct_fct3High Concern",      "Racial Resent. x Oth x Norms: High") %>%


        str_replace("race.*black",            "Race: Black") %>%
        str_replace("race.*hispanic",         "Race: Hispanic") %>%
        str_replace("race.*other",            "Race: Other") %>%
        str_replace("race.*white",            "Race: White") %>%
        str_replace("race.*native_american",  "Race: Native American") %>%
        str_replace("race.*other",            "Race: Other") %>%
        str_replace("race4",                  "Race") %>%

        str_replace("income(?:16|20|24)?",             "Income") %>%
        str_replace("pol_attn(?:16|20|24)?",           "Political Attention") %>%

        str_replace("racial_resent(?:16|20|24)?",             "Racial Resentment") %>%
        str_replace("sexism(?:16|20|24)?",             "Hostile Sexism") %>%
        str_replace("authorit(?:16|20|24)?",           "Authoritarianism") %>%

        str_replace("nchar_nr_prob_tot_log|nchar_problems_.*_.*",  "Expressive Engagement 2016") %>%
        str_replace("nonresp_nchar_all_log|nchar_align_.*ihs",  "Expressive Alignment 2016") %>%

        str_replace("nchar_like_dem_ihs",     "# Char (For Clinton)") %>%
        str_replace("nchar_like_rep_ihs",     "# Char (For Trump)") %>%
        str_replace("nchar_dislike_dem_ihs",  "# Char (Against Clinton)") %>%
        str_replace("nchar_dislike_rep_ihs",  "# Char (Against Trump)") %>%

        str_replace("nchar_nr_prob_tot",  "Expressive Engagement 2016") %>%
        str_replace("nonresp_nchar_all",  "Expressive Alignment 2016") %>%

        str_replace("vote_confirmed",     "Validated Turnout 2016") %>%
        str_replace("turnout20_bin",      "Validated Turnout 2020") %>%
        str_replace("vote_pres_dem",      "Vote Clinton") %>%
        str_replace("vote_pres_rep",      "Vote Trump") %>%

        str_replace("reg_intent",         "Reg/Vote Status") %>%
        str_replace("likely_vote",        "Likely Vote") %>%
        str_replace("mode",               "Mode")


}

# build header and model print function for anova tables

print_models <- function(anova_model){

    # get the chunk name automatically
    chunk_name <- opts_current$get("label")

    tidy_model      <- broom::tidy(anova_model)
    tidy_model$term <- convert_model(tidy_model$term)

    # Using glue_data for dynamic number of models
    models <- glue::glue_data(tidy_model,
                              "\\item Model <<1:nrow(tidy_model)>>: <<term>>",
                              .open = "<<", .close = ">>")

    # replace tilde with latex \sim
    models <- str_replace_all(models, "~", "$\\\\sim$")

    # Print the results with header and within itemize list
    glue::glue_collapse(
        c("\\noindent Models used in Table \\ref{tab:", chunk_name, "}
    \\begin{itemize}
  ", models,
          "\\end{itemize}"
        ),
        sep = "")
}


print_anova <- function(anova_model, caption){

    anova_model %>%
        mutate(`Pr(>Chi)` = `Pr(>Chi)` %>% scales::pvalue(accuracy = 0.00001)) %>%
        mutate_at(c("Resid. Dev", "Deviance"), round2) %>%
        mutate_at(c("Df", "Deviance", "Pr(>Chi)"), na_to_blank) %>%

        kableExtra::kable(format    = "latex",
                          booktabs  = TRUE,
                          digits    = 20,
                          escape = FALSE, # don't escape $ in $p$-value to \$p\$-value
                          caption = caption) %>%
        kableExtra::kable_styling(
            latex_options = c("hold_position")
        )

}
